package cn.net.httpclient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Consts;
import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.MessageConstraints;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.nio.charset.CodingErrorAction;
import java.security.cert.X509Certificate;
import java.util.Arrays;

@Component
@Scope("prototype")
public class HttpClientSystem {

    private static final Log log = LogFactory.getLog(HttpClientSystem.class);

    private int connectReq = 15000;

    private int connectTime = 15000;

    private int sockettime = 15000;

    private String ip = "47.92.5.200";//"103.95.207.156";//"103.95.207.156";//"47.92.5.200";//"103.95.207.76";

    private int port = 53535;//53535;//19870;

    private CloseableHttpClient client;

    private RequestConfig requestConfig;

    private HttpClientContext context;

    private CookieStore cookieStore;

    private void createClient() {
        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContextBuilder.create().loadTrustMaterial(null, (X509Certificate[] arg0, String arg1) ->
                    true).
                    build();
        } catch (Exception e) {
            log.error("create ssl exception", e);
        }

        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext, new
                String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, null, (String arg0, SSLSession arg1) -> true);

        SocketConfig socketConfig = SocketConfig
                .custom()
                .setTcpNoDelay(true)
                .build();
        MessageConstraints messageConstraints = MessageConstraints
                .custom()
                .setMaxHeaderCount(200)
                .setMaxLineLength(2000)
                .build();
        ConnectionConfig connectionConfig = ConnectionConfig
                .custom()
                .setMalformedInputAction(CodingErrorAction.IGNORE)
                .setUnmappableInputAction(CodingErrorAction.IGNORE)
                .setCharset(Consts.UTF_8)
                .setMessageConstraints(messageConstraints)
                .build();

        cookieStore = new BasicCookieStore();

        context = HttpClientContext.create();
        context.setCookieStore(cookieStore);

        HostnameVerifier hv = (String urlHostName, SSLSession session) -> true;

        RequestConfig defaultRequestConfig = RequestConfig
                .custom()
                .setCookieSpec(CookieSpecs.STANDARD_STRICT)
                .setExpectContinueEnabled(true)
                .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM,
                        AuthSchemes.DIGEST))
                .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
                .setConnectionRequestTimeout(connectReq)
                .setSocketTimeout(sockettime)
                .setConnectTimeout(connectTime)
                .build();

        this.requestConfig = RequestConfig.copy(defaultRequestConfig).build();

        this.client = HttpClients
                .custom()
                .setDefaultCookieStore(cookieStore)
                .setProxy(new HttpHost(this.ip, this.port))
                .setDefaultRequestConfig(defaultRequestConfig)
                .setSSLContext(sslcontext)
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setSSLHostnameVerifier(hv)
                .setDefaultSocketConfig(socketConfig)
                .setDefaultConnectionConfig(connectionConfig)
                .build();
    }

    public HttpClientSystem() {
        this.createClient();
    }

    public String get(HttpGet get) {
        CloseableHttpResponse response = null;
        String res;
        try {
            get.setConfig(requestConfig);
            response = this.client.execute(get);
            res = EntityUtils.toString(response.getEntity());
        } catch (ClientProtocolException e) {
            log.error(e.getMessage() + get.getURI().toString());
            return null;
        } catch (IOException e) {
            log.error(e.getMessage() + get.getURI().toString());
            return null;
        } finally {
            get.releaseConnection();
            get.abort();
            try {
                if (response != null) {
                    if (response.getEntity() != null)
                        EntityUtils.consume(response.getEntity());
                    response.close();
                }
            } catch (IOException e) {
                log.error("kill response exception :" + e.getMessage() + get.getURI().toString());
            }
        }
        return res;
    }

    public CloseableHttpResponse post(HttpPost post) {
        CloseableHttpResponse response = null;
        try {
            post.setConfig(requestConfig);
            response = this.client.execute(post);
        } catch (ClientProtocolException e) {
            log.error(e.getMessage() + post.getURI().toString());
            return null;
        } catch (IOException e) {
            log.error(e.getMessage() + post.getURI().toString());
            return null;
        } finally {
            post.releaseConnection();
            post.abort();
            try {
                if (response != null) {
                    if (response.getEntity() != null)
                        EntityUtils.consume(response.getEntity());
                    response.close();
                }
            } catch (IOException e) {
                log.error("kill response exception :" + e.getMessage() + post.getURI().toString());
            }
        }
        return response;
    }

    public CookieStore cookieStore() {
        return cookieStore;
    }

    public void close() {
        try {
            this.client.close();
        } catch (IOException e) {
        }
    }
}